#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string>
#include <string.h>


// 定义常见业务数量 
#define BUSINESS_TYPE_NUM 4 
// 定义服务窗口数量
#define WINDOW_NUM 4 
// 定义营业时间（分钟） 
#define WORKING_MINUTES 480 

//修改营业时间：用xx：xx时间制 还有要显示出是哪个窗口在为客户服务 排队中还有几人在等待 让程序慢点运行getche（）
//修改总时间

char* business_types[BUSINESS_TYPE_NUM] = {"存款", "取款", "挂失", "还贷"};

// 客户结构体，用于表示客户的相关信息
typedef struct Customer {
    int arrival_time;  // 到达银行时间（分钟） 
    int customer_id;   // 客户编号
    char business_type[20];  // 办理的业务类型
    int end_service_time; // 业务结束时间
    struct Customer* next;  // 指向下一个客户的指针
} Customer;

// 银行模拟结构体，包含整个模拟需要的相关数据
typedef struct BankSimulation {
    Customer* waiting_queue;  // 客户等待队列
    Customer* service_windows[WINDOW_NUM];  // 每个服务窗口正在服务的客户指针数组
    int total_customers;  // 总共的客户数量
    int total_dwell_time;  // 所有客户逗留的总时间，这个需要在办理业务时间里体现 还没实现 
    int window_customers_count[WINDOW_NUM];  // 每个窗口办理的客户数量统计数组
    int business_count_per_window[WINDOW_NUM][BUSINESS_TYPE_NUM];  // 每个窗口办理每种业务的数量统计二维数组
    int total_service_time; // 新增：所有客户办理业务的总时间
} BankSimulation;

// 函数声明
// 初始化银行模拟结构体
void init_bank_simulation(BankSimulation* bank) {
    bank->waiting_queue = NULL;
    int i;
    for (i = 0; i < WINDOW_NUM; i++) {
        bank->service_windows[i] = NULL;
    }
    bank->total_customers = 0;
    bank->total_dwell_time = 0;
    bank->total_service_time = 0; // 初始化总服务时间为 0
    for ( i = 0; i < WINDOW_NUM; i++) {
        bank->window_customers_count[i] = 0;
        int j;
        for ( j = 0; j < BUSINESS_TYPE_NUM; j++) {
            bank->business_count_per_window[i][j] = 0;
        }
    }
}
// 创建新客户并返回其指针
Customer* create_customer(int arrival_time, int customer_id, const char* business_type) {
    Customer* new_customer = (Customer*)malloc(sizeof(Customer));
    if (new_customer == NULL) {
        printf("内存分配失败！\n");
        return NULL;
    }
    new_customer->arrival_time = arrival_time;
    new_customer->customer_id = customer_id;
    strcpy(new_customer->business_type, business_type);
    new_customer->end_service_time = 0; // 初始化业务结束时间为 0
    new_customer->next = NULL;
    return new_customer;
}

// 将客户加入等待队列（入队操作）
void enqueue(BankSimulation* bank, Customer* customer) {
    if (bank->waiting_queue == NULL) {
        bank->waiting_queue = customer;
    } else {
        Customer* current = bank->waiting_queue;
        while (current->next!= NULL) {
            current = current->next;
        }
        current->next = customer;
    }
}
// 从等待队列取出队首客户（出队操作）
Customer* dequeue(BankSimulation* bank) {
    if (bank->waiting_queue == NULL) {
        return NULL;
    }
    Customer* front_customer = bank->waiting_queue;
    bank->waiting_queue = bank->waiting_queue->next;
    front_customer->next = NULL;
    return front_customer;
}

// 模拟客户随机到达银行并加入等待队列
void generate_customers(BankSimulation* bank) {
    srand((unsigned int)time(NULL));
    int current_time;
    for (current_time = 0; current_time < WORKING_MINUTES; current_time++) {
        if (rand() % 10 < 2) {  
            int customer_id = bank->total_customers + 1;
            int business_index = rand() % BUSINESS_TYPE_NUM;
            char* business_type = business_types[business_index];
            Customer* new_customer = create_customer(current_time, customer_id, business_type);
            enqueue(bank, new_customer);
            bank->total_customers++;
        }
    }
}


// 模拟服务窗口处理客户业务
int business_service_time_ranges[BUSINESS_TYPE_NUM][2] = {
    {3, 6},  // 存款
    {2, 5},  // 取款
    {3, 7}, // 挂失
    {4, 8}   // 还贷
};

void process_customers(BankSimulation* bank) {
    int current_time;
    for (current_time = 0; current_time < WORKING_MINUTES; current_time++) {
        int window_index;
        for (window_index = 0; window_index < WINDOW_NUM; window_index++) {
            if (bank->service_windows[window_index] == NULL) {
                // 窗口空闲，从等待队列取客户来服务
                Customer* customer = dequeue(bank);
                if (customer!= NULL) {
                    bank->service_windows[window_index] = customer;
                    // 根据客户办理的业务类型确定服务时间
                    int business_index;
                    for (business_index = 0; business_index < BUSINESS_TYPE_NUM; business_index++) {
                        if (strcmp(customer->business_type, business_types[business_index]) == 0) {
                            int service_time_min = business_service_time_ranges[business_index][0];
                            int service_time_max = business_service_time_ranges[business_index][1];
                            int service_time = (rand() % (service_time_max - service_time_min + 1)) + service_time_min;
                            // 记录客户开始接受服务的时间（包含当前时间点）
                            int start_service_time = current_time; 
                            // 更新客户业务结束时间，考虑跨时间点情况，确保时间准确
                            customer->end_service_time = current_time + service_time;
                            if (customer->end_service_time >= WORKING_MINUTES) {
                                // 如果业务结束时间超过营业时间，调整为营业时间结束时间
                                customer->end_service_time = WORKING_MINUTES;
                            }
                            bank->window_customers_count[window_index]++;
                            bank->business_count_per_window[window_index][business_index]++;
                            // 将业务办理时间累加到总服务时间中
                            bank->total_service_time += service_time; 
                            printf("******************************************\n");
                            printf("\t正在为%d号客户办理业务....\n", customer->customer_id);
                            printf("\t%d号客户办理的业务类型为：%s\n", customer->customer_id, customer->business_type);
                            printf("\t%d号客户到达时间为：%d\n", customer->customer_id, customer->arrival_time);
                            printf("******************************************\n");
                            //getche();//显示几条之后需要输入任意字符继续输出
                            break;
                        }
                    }
                }
            } else {
                // 窗口正在服务客户，检查是否服务完成
                Customer* customer = bank->service_windows[window_index];
                if (customer->end_service_time <= current_time) {
                    bank->service_windows[window_index] = NULL;
                    // 此处准确计算客户实际接受服务的时间，考虑跨时间点等边界情况
                    int start_service_time;
                    int actual_service_time = customer->end_service_time - start_service_time;
                    bank->total_dwell_time += actual_service_time;
                }
            }
        }
    }
}

// 输出模拟结果
void print_results(BankSimulation* bank) {
    double average_service_time = (double)bank->total_service_time / bank->total_customers; // 计算平均服务时间
    printf("总时间%d分钟\n",bank->total_dwell_time);
    printf("总客户数%d人\n",bank->total_customers);
    printf("客户办理业务的平均时间：%.2f分钟\n", average_service_time);
    printf("每个窗口办理的客户数：\n");
    int i;
    for (i = 0; i < WINDOW_NUM; i++) {
        printf("窗口 %d: %d 个\n", i + 1, bank->window_customers_count[i]);
    }
    printf("每个窗口办理的每种业务数：\n");
    for (i = 0; i < WINDOW_NUM; i++) {
        printf("窗口 %d:\n", i + 1);
        int j;
        for (j = 0; j < BUSINESS_TYPE_NUM; j++) {
            printf("  %s: %d 个\n", business_types[j], bank->business_count_per_window[i][j]);
        }
    }
}

// 将客户的排队小票信息打印到文件
void print_ticket_to_file(Customer* customer, int queue_size, FILE* file) {
    fprintf(file, "客户编号: %d\n", customer->customer_id);
    fprintf(file, "到达时间: %d分钟（从营业开始算）\n", customer->arrival_time);
    fprintf(file, "办理业务: %s\n", customer->business_type);
    fprintf(file, "前方还有 %d 人排队\n", queue_size - 1);  
    fprintf(file, "----------------------\n");
}
// 释放内存，避免内存泄漏
void free_memory(BankSimulation* bank) {
    Customer* current = bank->waiting_queue;
    Customer* next;
    while (current!= NULL) {
        next = current->next;
        free(current);
        current = next;
    }
    int i;
    for (i = 0; i < WINDOW_NUM; i++) {
        if (bank->service_windows[i]!= NULL) {
            free(bank->service_windows[i]);
        }
    }
}



// 主函数，程序入口
int main() {
    BankSimulation bank;
    init_bank_simulation(&bank);
    generate_customers(&bank);
    process_customers(&bank);
    print_results(&bank);
    FILE* file = fopen("ticket.txt", "w");
    if (file == NULL) {
        printf("文件打开失败！\n");
        return 1;
    }
    Customer* current = bank.waiting_queue;
    int queue_size = 0;
    while (current!= NULL) {
        queue_size++;
        current = current->next;
    }
    current = bank.waiting_queue;
    while (current!= NULL) {
        print_ticket_to_file(current, queue_size, file);
        current = current->next;
    }

    fclose(file);
    free_memory(&bank);

    return 0;
}